package com.ias.redis.support;

import com.ias.redis.config.CacheRedisProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

@Slf4j
public class RedisCacheManager implements CacheManager {
    
    private static final ConcurrentMap<String, Cache> cacheMap = new ConcurrentHashMap<>();

    private final CacheRedisProperties cacheRedisProperties;

    private final RedisTemplate<Object, Object> redisTemplate;

    private boolean dynamic = true;

    private final Set<String> cacheNames;

    {
        cacheNames = new HashSet<>();
        cacheNames.add(CacheNames.CACHE_1MIN);
        cacheNames.add(CacheNames.CACHE_5MINS);
        cacheNames.add(CacheNames.CACHE_15MINS);
        cacheNames.add(CacheNames.CACHE_60MINS);
        cacheNames.add(CacheNames.CACHE_12HOUR);
        cacheNames.add(CacheNames.CACHE_24HOUR);
        cacheNames.add(CacheNames.CACHE_PERMANENT);
    }

    public RedisCacheManager(CacheRedisProperties cacheRedisProperties,
                            RedisTemplate<Object, Object> redisTemplate) {
        super();
        this.cacheRedisProperties = cacheRedisProperties;
        this.redisTemplate = redisTemplate;
        this.dynamic = cacheRedisProperties.isDynamic();
    }

    //——————————————————————— 缓存工具方法 ——————————————————————

    /**
     * 清除所有缓存
     */
    public void clearAllCache() {
        log.info("[L1_CacheManager] RedisCacheManager clear all cache");
        for (Cache cache : cacheMap.values()) {
            cache.clear();
        }
    }

    /**
     * 清除指定缓存
     *
     * @param cacheName 缓存名称，null则清空所有缓存
     */
    public void clearCache(String cacheName) {
        if (cacheName == null) {
            clearAllCache();
            return;
        }
        
        Cache cache = cacheMap.get(cacheName);
        if (cache != null) {
            log.info("[L1_CacheManager] RedisCacheManager clear cache: {}", cacheName);
            cache.clear();
        }
    }

    /**
     * 清除指定缓存的指定key
     *
     * @param cacheName 缓存名称
     * @param key 缓存key
     */
    public void evictCache(String cacheName, Object key) {
        Cache cache = cacheMap.get(cacheName);
        if (cache != null) {
            log.info("[L1_CacheManager] RedisCacheManager evict cache: {} key: {}", cacheName, key);
            cache.evict(key);
        }
    }

    //—————————————————————————— core —————————————————————————

    @Override
    public Cache getCache(String name) {
        Cache cache = cacheMap.get(name);
        if (cache != null) {
            return cache;
        }
        
        if (!dynamic && !cacheNames.contains(name)) {
            return null;
        }

        cache = new RedisCache(name, redisTemplate, cacheRedisProperties);
        Cache oldCache = cacheMap.putIfAbsent(name, cache);
        log.info("[L1_CacheManager] RedisCacheManager create cache instance, the cache name is : {}", name);
        return oldCache == null ? cache : oldCache;
    }

    @Override
    public Collection<String> getCacheNames() {
        return this.cacheNames;
    }
} 